﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.XPath;
using System.Xml;
using System.Collections;
using System.Web.UI;
using System.Web;
using Microsoft.SharePoint;
using System.IO;

namespace beyCoo4Sharepoint
{
    class beyCooXmlSelecter
    {
        public Hashtable selectedEntity = new Hashtable();
        public Hashtable selectedRtf = new Hashtable();
        
        
        //constructor (obsolete)
        public beyCooXmlSelecter(string entityString, List<string> xPathEntity, string rtfString, string rtfEntityKey)
        {
            this.selectedEntity = EntitySelecter(entityString, xPathEntity);
            this.selectedRtf = EntitySelecter(rtfString, rtfEntityKey);
        }

        //constructor
        public beyCooXmlSelecter(string entityString, List<string> xPathEntity)
        {
            this.selectedEntity = EntitySelecter(entityString, xPathEntity);
        }

        //constructor
        public beyCooXmlSelecter(string rtfString, string xPathRTF)
        {
            this.selectedRtf = EntitySelecter(rtfString, xPathRTF);
        }

        /// <summary>
        /// gets the results from the bexcoo response xml
        /// </summary>
        /// <param name="resultstring"></param>
        /// <param name="xPathEntity"></param>
        /// <returns></returns>
        private Hashtable EntitySelecter(string resultstring, List<string> xPathEntity)
        {

            Hashtable resultList = new Hashtable();
            XmlDocument resultDoc = new XmlDocument();
            resultDoc.LoadXml(resultstring);
            //check the response document to see if there are still transaction left for this customerkey
            bool limitExceeded = checkIfLimitExceeded(resultDoc);
            XmlNode root = resultDoc.DocumentElement;
            XmlNamespaceManager nsmgr = new XmlNamespaceManager(resultDoc.NameTable);
            nsmgr.AddNamespace("bc", "http://beycoo.com/xml/schema");

            if (!limitExceeded)
            {
                foreach (string xPath in xPathEntity)
                {

                    string[] sep = { "->" };
                    string[] xpathSeparated = xPath.Split(sep, 2, StringSplitOptions.RemoveEmptyEntries);
                    //first look if expression before "->" starts with "XPath:", then treat as XPath directly, if not, then normal mapping applied (Person -> person)
                    //and standard XPath should be loaded for this entity
                    if (xpathSeparated[0].Length > 0)
                    {
                        if (xpathSeparated[0].ToLower().StartsWith("xpath:"))
                        {
                            string[] sep2 = { ":" };
                            string[] xpathSeparated2 = xpathSeparated[0].Split(sep2, 2, StringSplitOptions.RemoveEmptyEntries);
                            //put in the XPath expression, which resides in xpathSeparated2[1] as XPath to process resultdoc
                            if (xpathSeparated2[1].Length > 0)
                            {
                                StringBuilder entities = new StringBuilder();
                                XmlNodeList nodeList = root.SelectNodes(xpathSeparated2[1].ToLower(), nsmgr);
                                foreach (XmlNode node in nodeList)
                                {
                                    entities.Append(node.Value.ToString() + ";#");
                                }

                                resultList.Add(xpathSeparated[1], entities.ToString());
                            }
                        }
                        else
                        //expression doesn't start with "XPath:", put in standard xpath template for the requested entity 
                        {
                            StringBuilder entities = new StringBuilder();
                            string templateString = "";

                            if (xpathSeparated[1].Contains("(") && xpathSeparated[1].Contains(")"))
                            {
                                string[] sep3 = { "(", ")" };
                                string[] limitedResults = xpathSeparated[1].Split(sep3, StringSplitOptions.RemoveEmptyEntries);
                                int nr = Int16.Parse(limitedResults[1]);
                                nr = nr + 1;
                                templateString = "(//bc:named-entity/bc:categories/bc:category[text()=\"" + limitedResults[0].ToLower() + "\"]/../../@display-name)[position()<" + nr + "]";
                                XmlNodeList nodeList = root.SelectNodes(templateString, nsmgr);
                                foreach (XmlNode node in nodeList)
                                {
                                    entities.Append(node.Value.ToString() + ";#");
                                }
                                resultList.Add(limitedResults[0], entities.ToString());
                            }
                            else
                            {
                                templateString = "//bc:named-entity/bc:categories/bc:category[text()=\"" + xpathSeparated[0].ToLower() + "\"]/../../@display-name";
                                XmlNodeList nodeList = root.SelectNodes(templateString, nsmgr);
                                foreach (XmlNode node in nodeList)
                                {
                                    entities.Append(node.Value.ToString() + ";#");
                                }
                                resultList.Add(xpathSeparated[1], entities.ToString());
                            }


                        }
                    }

                } 
            }

            return resultList;
        }

        private bool checkIfLimitExceeded(XmlDocument resultDoc)
        {
            bool limitExceeded = false;
            string XPathLimitExceeded = "/beycoo/@state";
            XmlNodeList status = resultDoc.SelectNodes(XPathLimitExceeded);
            foreach (XmlNode node in status)
            {
                if (node.Value.ToString() == "104")
                {
                    limitExceeded = true;
                    beyCooLogger.LogError("beyCooError", "The maximum amount of free transaction has been reached!");                    
                }
            }

            return limitExceeded;
        }

        /// <summary>
        /// select the rtf entities from the beyCoo response doc
        /// </summary>
        /// <param name="resultstring"></param>
        /// <param name="xPathRTF"></param>
        /// <returns></returns>
        private Hashtable EntitySelecter(string resultstring, string xPathRTF)
        {
            string rtfEntityKey = "Enterprise Keywords";
            string targetColName = "";
            int nr = -1;
            Hashtable resultList = new Hashtable();
            XmlDocument resultDoc = new XmlDocument();
            resultDoc.LoadXml(resultstring);
            bool limitExceeded = checkIfLimitExceeded(resultDoc);
            XmlNode root = resultDoc.DocumentElement;
            XmlNamespaceManager nsmgr = new XmlNamespaceManager(resultDoc.NameTable);
            nsmgr.AddNamespace("bc", "http://beycoo.com/xml/schema");
            StringBuilder entities = new StringBuilder();
            if (!limitExceeded)
            {
                if (xPathRTF.Length > 0)
                {
                    string[] seprtf = { "(", ")" };
                    string[] mappingRTF = xPathRTF.Split(seprtf, StringSplitOptions.RemoveEmptyEntries);
                    if (mappingRTF.Count<string>() > 1)
                    {
                        targetColName = mappingRTF[0];
                        nr = Int16.Parse(mappingRTF[1]);
                    }
                    else
                    //mapping only contains number, set targetColName to "Enterprise Keywords"
                    {
                        targetColName = rtfEntityKey;
                        nr = Int16.Parse(mappingRTF[0]);
                    }
                    XPathNavigator nav = resultDoc.CreateNavigator();
                    XPathExpression xpathLimitedSelectRTF = XPathExpression.Compile("/beycoo/bc:document/bc:relevant-terms/bc:relevant-term/bc:occurrences/bc:occurrence");
                    xpathLimitedSelectRTF.SetContext(nsmgr);
                    xpathLimitedSelectRTF.AddSort("@score", XmlSortOrder.Descending, XmlCaseOrder.None, "", XmlDataType.Number);
                    XPathNodeIterator it = nav.Select(xpathLimitedSelectRTF);
                    string lastattr = "somestringthatdoesntmatchwithanyotherstringbymistake";
                    int i = 0;
                    while (it.MoveNext() && i < nr)
                    {
                        if (it.Current.HasAttributes)
                        {

                            string attr = it.Current.GetAttribute("original", "");
                            if (!attr.Equals(lastattr) && (!attr.StartsWith(lastattr)))
                            {
                                lastattr = attr;
                                entities.Append(attr + ";#");
                                i++;
                            }
                        }
                    }

                    resultList.Add(targetColName, entities.ToString());

                }
                else
                {
                    string xpathSelectRTF = "//bc:relevant-terms/bc:relevant-term/@display-name";
                    XmlNodeList nodeList = root.SelectNodes(xpathSelectRTF, nsmgr);
                    foreach (XmlNode node in nodeList)
                    {
                        entities.Append(node.Value.ToString() + ";#");
                    }
                    resultList.Add(rtfEntityKey, entities.ToString());
                } 
            }

            return resultList;
        }

    }
}
